#include "MP3Decoder.h"

#include "decoder_fs.h"
#include "decoder_thread.h"

#include <cstring>
#include <cstdio>

static signed int scale(mad_fixed_t sample);

void mp3DecodeThreadFunc(void *arg);
enum mad_flow header_preprocess(void *userData, struct mad_header const *header);
enum mad_flow input(void *userData, struct mad_stream *stream);
enum mad_flow header(void *userData, struct mad_header const *header);
enum mad_flow output(void *userData, struct mad_header const *header, struct mad_pcm *pcm);

MP3Decoder::~MP3Decoder()
{
    close();
}

bool MP3Decoder::open(const char *path)
{
    sizeof(*this);

    if (path == nullptr)
        return false;

    file = DecoderFs::openFile(path);
    if (file == nullptr)
        return false;

    length = DecoderFs::sizeofFile(file);

    pcmBufferFrameSize = 0;

    durationFrac = 0;
    durationSec = 0;

    timelapseFrac = 0;
    timelapseSec = 0;

    destSec = -1;
    destSeted = false;

    // 创建mad解码器
    decoder = new struct mad_decoder;
    memset(decoder, 0, sizeof(struct mad_decoder));

    // 创建原始数据缓冲区
    buffer = new uint8_t[DECODER_BUFFER_SZIE];

    // 遍历帧头
    decodePreprocess();
    totalSec = (1.0f * durationFrac / MAD_TIMER_RESOLUTION) + durationSec; // 计算总时长

    // 创建信号量
    dataReadySem = DecoderThread::semCreate(0);
    decodeReadySem = DecoderThread::semCreate(1);

    decodeThreadState = true;

    // 创建解码线程
    decodeThread = DecoderThread::threadCreate((void *)mp3DecodeThreadFunc, this);

    return true;
}

/**
 * @brief 阻塞读取解码数据帧
 * @retval 数据缓冲区，需要使用delete[]释放
 * @note 数据帧大小固定为getFrameSize()
 */
uint8_t *MP3Decoder::readDecodeFrame(void)
{
    DecoderThread::semWait(dataReadySem); // 等待数据就绪信号量

    if (decodeThreadState == false)
        return nullptr;

    size_t size = pcmBufferFrameSize * 2 * nchannels;

    uint8_t *buf = new uint8_t[size];
    memcpy(buf, pcmBuffer, size);

    DecoderThread::semPost(decodeReadySem); // 发送解码就绪信号量(进行下一次解码)

    return buf;
}

/**
 * @brief 设置mp3当前播放时间点
 * @param _destSec 目标点秒数
 */
void MP3Decoder::setCurrent(uint32_t _destSec)
{
    if (_destSec < totalSec)
    {
        destSec = _destSec;
        destSeted = true;
    }
}

/**
 * @brief 关闭解码器并释放资源
 */
void MP3Decoder::close(void)
{
    if (file == nullptr)
        return;

    decodeThreadState = false;

    DecoderThread::semPost(dataReadySem);
    DecoderThread::semPost(decodeReadySem);

    DecoderThread::threadJoin(decodeThread);

    DecoderThread::mSleep(100);

    DecoderThread::semDestroy(dataReadySem);
    DecoderThread::semDestroy(decodeReadySem);

    delete[] pcmBuffer;
    delete[] buffer;

    DecoderFs::closeFile(file);
    file = nullptr;
}

/**
 * @brief mp3前处理，遍历帧头
 */
int MP3Decoder::decodePreprocess(void)
{
    mad_decoder_init((struct mad_decoder *)decoder, this,
                     input, header_preprocess /* header */, nullptr /* filter */, nullptr, /* output */
                     nullptr, /* error */ nullptr /* message */);

    int result = mad_decoder_run((struct mad_decoder *)decoder, MAD_DECODER_MODE_SYNC);
    mad_decoder_finish((struct mad_decoder *)decoder);

    return result;
}

/**
 * @brief 解码线程
 */
void mp3DecodeThreadFunc(void *arg)
{
    MP3Decoder *mp3Decoder = (MP3Decoder *)arg;

    // 文件偏移至开头
    DecoderFs::seekFile(mp3Decoder->file, 0, DecoderFs::SeekSet);
    mp3Decoder->length = DecoderFs::sizeofFile(mp3Decoder->file);
    memset(mp3Decoder->decoder, 0, sizeof(struct mad_decoder));

    mad_decoder_init((struct mad_decoder *)mp3Decoder->decoder, mp3Decoder,
                     input, header, nullptr, output, nullptr, nullptr); // 初始化解码器

    int ret = mad_decoder_run((struct mad_decoder *)mp3Decoder->decoder, MAD_DECODER_MODE_SYNC);
    mad_decoder_finish((struct mad_decoder *)mp3Decoder->decoder);

    mp3Decoder->decodeThreadState = false;
    DecoderThread::threadExit(mp3Decoder);
}

/**
 * @brief mp3帧头遍历
 */
enum mad_flow header_preprocess(void *userData, struct mad_header const *header)
{
    MP3Decoder *mp3Decoder = (MP3Decoder *)userData;

    /* Count duration */
    mp3Decoder->durationFrac += header->duration.fraction;
    mp3Decoder->durationSec += header->duration.seconds;

    if (mp3Decoder->pcmBufferFrameSize == 0)
    {
        mp3Decoder->nchannels = MAD_NCHANNELS(header);
        mp3Decoder->sampleRate = header->samplerate;
        mp3Decoder->pcmBufferFrameSize = MAD_NSBSAMPLES(header) * 32; // 帧大小(采样数/帧), 32为MP3固定划分的32个子频带

        mp3Decoder->pcmBuffer = new uint8_t[mp3Decoder->pcmBufferFrameSize * 2 * mp3Decoder->nchannels];
    }

    /* Do not decode */
    return MAD_FLOW_IGNORE;
}

/**
 * @brief mp3解码数据输入回调函数
 */
enum mad_flow input(void *userData, struct mad_stream *stream)
{
    MP3Decoder *mp3Decoder = (MP3Decoder *)userData;

    if (mp3Decoder->length == 0)
        return MAD_FLOW_STOP;

    // 计算文件偏移(不完整帧需要在下一次读取解码)
    int seekPos = stream->bufend - stream->next_frame;
    DecoderFs::seekFile(mp3Decoder->file, -seekPos, DecoderFs::SeekCur);
    mp3Decoder->length += seekPos;

    // 读取文件
    size_t size = DecoderFs::readFile(mp3Decoder->file, mp3Decoder->buffer, DECODER_BUFFER_SZIE);
    if (size == 0)
        return MAD_FLOW_STOP;

    mad_stream_buffer(stream, mp3Decoder->buffer, size);
    mp3Decoder->length -= size;

    return MAD_FLOW_CONTINUE;
}

/**
 * @brief mp3解码帧头读取后回调函数
 */
enum mad_flow header(void *userData, struct mad_header const *header)
{
    enum mad_flow ret = MAD_FLOW_CONTINUE;
    MP3Decoder *mp3Decoder = (MP3Decoder *)userData;

    if (mp3Decoder->decodeThreadState == false)
        return MAD_FLOW_STOP;

    // 设置播放时间点
    if (mp3Decoder->destSeted != false)
    {
        // 文件偏移至开头
        DecoderFs::seekFile(mp3Decoder->file, 0, DecoderFs::SeekSet);

        // 读取文件
        size_t size = DecoderFs::readFile(mp3Decoder->file, mp3Decoder->buffer, DECODER_BUFFER_SZIE);

        // 重新填装解码buff
        auto madDecoder = (struct mad_decoder *)mp3Decoder->decoder;
        mad_stream_buffer(&(madDecoder->sync->stream), mp3Decoder->buffer, size);

        mp3Decoder->timelapseSec = 0;
        mp3Decoder->timelapseFrac = 0;
        mp3Decoder->destSeted = false;
    }

    // 计算当前播放时间点
    mp3Decoder->timelapseFrac += header->duration.fraction;
    mp3Decoder->timelapseSec += header->duration.seconds;
    mp3Decoder->currentSec = (1.0f * mp3Decoder->timelapseFrac / MAD_TIMER_RESOLUTION) + mp3Decoder->timelapseSec;

    if (mp3Decoder->destSec >= 0)
    {
        if (mp3Decoder->currentSec < mp3Decoder->destSec) // 设置的时间点大于当前时间点
            ret = MAD_FLOW_IGNORE;                        // 不解码
        else
            mp3Decoder->destSec = -1;
    }

    return ret;
}

/**
 * @brief mp3解码数据输出回调函数
 */
enum mad_flow output(void *userData, struct mad_header const *header, struct mad_pcm *pcm)
{
    MP3Decoder *mp3Decoder = (MP3Decoder *)userData;

    DecoderThread::semWait(mp3Decoder->decodeReadySem); // 等待解码就绪信号量

    uint8_t nchannels = pcm->channels;
    uint16_t nsamples = pcm->length;
    mad_fixed_t const *left_ch = pcm->samples[0];
    mad_fixed_t const *right_ch = pcm->samples[1];

    uint8_t *outputBuffer = mp3Decoder->pcmBuffer;

    for (int i = 0; i < nsamples; i++)
    {
        signed int sample;

        sample = scale(*left_ch++); // 获取左声道数据
        *(outputBuffer++) = sample >> 0;
        *(outputBuffer++) = sample >> 8;
        if (nchannels == 2)
        {
            sample = scale(*right_ch++); // 获取右声道数据
            *(outputBuffer++) = sample >> 0;
            *(outputBuffer++) = sample >> 8;
        }
    }

    // 发送数据就绪信号量
    DecoderThread::semPost(mp3Decoder->dataReadySem);

    return MAD_FLOW_CONTINUE;
}

/**
 * @brief mp3解码数据缩放
 */
static signed int scale(mad_fixed_t sample)
{
    sample += (1L << (MAD_F_FRACBITS - 16));

    if (sample >= MAD_F_ONE)
        sample = MAD_F_ONE - 1;
    else if (sample < -MAD_F_ONE)
        sample = -MAD_F_ONE;

    return sample >> (MAD_F_FRACBITS + 1 - 16);
}
